﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Threading;
using C4F.VistaP2P.Common;
using System.Drawing;

namespace C4F.VistaP2P.WPF.Chat
{
    /// <summary>
    /// Interaction logic for Picture.xaml
    /// </summary>
    [ToolboxBitmap(typeof(resfinder), "C4F_P2PWPFControls.c4f.bmp")]
    public partial class ChatControl : UserControl
    {

        #region Dependency Properties
        /// <summary>
        /// The dependency property for the Sending Text control. The dependency property is used so we can have databinding using the smart tag adorner
        /// </summary>
        public static  DependencyProperty SendTextProperty = DependencyProperty.Register(
           "SendText", typeof(TextBox), typeof(ChatControl), new PropertyMetadata(null, new PropertyChangedCallback(OnSendTextChanged)));
        
                
        /// <summary>
        /// set and get the textbox control to used for inputting text that the chat control should use 
        /// </summary>
        public TextBox SendText
        {
            get
            {
                try
                {
                    return (TextBox)this.Dispatcher.Invoke(
                       System.Windows.Threading.DispatcherPriority.Normal,
                       (DispatcherOperationCallback)delegate { return GetValue(SendTextProperty); },
                       SendTextProperty);
                }
                catch
                {

                    return (TextBox)SendTextProperty.DefaultMetadata.DefaultValue;
                }
            }
            set
            {
                Dispatcher.Invoke(DispatcherPriority.Normal,
                  (SendOrPostCallback)delegate { SetValue(SendTextProperty, value); },
                  value);
            }
        }

        /// <summary>
        /// This function is called when the SendTextProperty is changed.
        /// Update the event handlers listening for carriage returns in the textbox so we can send a message.
        /// </summary>
        private static void OnSendTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ChatControl nm = (ChatControl)d;
            if (e.OldValue != null)
            {
                //unregister from the old one...
                TextBox oldText = (TextBox)e.NewValue;
                oldText.TextChanged -= new TextChangedEventHandler(nm._tbNewMessage_TextChanged);
            }
            //register for the new events.
            TextBox newText = (TextBox)e.NewValue;
            newText.TextChanged += new TextChangedEventHandler(nm._tbNewMessage_TextChanged);

        }

        /// <summary>
        /// The dependency property for the Sending Text control. The dependency property is used so we can have databinding using the smart tag adorner
        /// </summary>
        public static  DependencyProperty MessageLogProperty = DependencyProperty.Register(
           "MessageLog", typeof(TextBox), typeof(ChatControl));
        
        /// <summary>
        /// Set or get the control to use as a messagelog.  This contains the messages received so far.
        /// </summary>
        public TextBox MessageLog
        {
            get
            {
                try
                {
                    return (TextBox)this.Dispatcher.Invoke(
                       System.Windows.Threading.DispatcherPriority.Normal,
                       (DispatcherOperationCallback)delegate { return GetValue(MessageLogProperty); },
                       MessageLogProperty);
                }
                catch
                {

                    return (TextBox)MessageLogProperty.DefaultMetadata.DefaultValue;
                }
            }
            set
            {
                Dispatcher.Invoke(DispatcherPriority.Normal,
                  (SendOrPostCallback)delegate { SetValue(MessageLogProperty, value); },
                  value);
            }
        }


        /// <summary>
        /// The dependency property for the Send Button control. The dependency property is used so we can have databinding using the smart tag adorner
        /// </summary>
        public static  DependencyProperty SendButtonProperty = DependencyProperty.Register(
          "SendButton", typeof(Button), typeof(ChatControl), new PropertyMetadata(null, new PropertyChangedCallback(OnSendButtonChanged)));

        /// <summary>
        /// Get or set the control to use as the send button.
        /// </summary>
        public Button SendButton
        {
            get
            {
                try
                {
                    return (Button)this.Dispatcher.Invoke(
                       System.Windows.Threading.DispatcherPriority.Normal,
                       (DispatcherOperationCallback)delegate { return GetValue(SendButtonProperty); },
                       SendButtonProperty);
                }
                catch
                {

                    return (Button)SendButtonProperty.DefaultMetadata.DefaultValue;
                }
            }
            set
            {                
                Dispatcher.Invoke(DispatcherPriority.Normal,
                  (SendOrPostCallback)delegate { SetValue(SendButtonProperty, value); },
                  value);
            }
        }
      

      
        /// <summary>
        /// Update the events for the chat contol when the button changes.
        /// </summary>
        /// <param name="d">the chat control</param>
        /// <param name="e">the old and new buttons</param>
        private static void OnSendButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ChatControl nm = (ChatControl)d;
            if (e.OldValue != null)
            {
                //unregister from the old one...
                Button oldButton = (Button)e.NewValue;
                oldButton.Click -= new RoutedEventHandler(nm._SendText_Click);
            }
            //register for the new events.
            Button newButton = (Button)e.NewValue;
            newButton.Click += new RoutedEventHandler(nm._SendText_Click);
        }
        #endregion

      

        /// <summary>
        /// default construstor that just initializes the controls
        /// </summary>
        public ChatControl()
        {
            InitializeComponent();         
        }

        /// <summary>
        /// Hooks up the default buttons and chat controls if they were not set at design time.
        /// </summary>
        /// <param name="sender">unused</param>
        /// <param name="e">unused</param>
        private void _Chat_Loaded(object sender, RoutedEventArgs e)
        {
            if (SendText == null)
            {
                SendText = tbSendMessage;
            }

            if (SendButton == null)
            {
                SendButton = btnSendText;
            }

            if (MessageLog == null)
            {
                MessageLog = tbMessageLog;
            }

            SendButton.IsEnabled = false;
            MessageLog.IsEnabled = false;            
        }
        /// <summary>
        /// look for a carriage return "\r\n" so we can send out the text message when the user hits enter in the textbox.
        /// </summary>
        /// <param name="sender">the textbox that changed</param>
        /// <param name="e">unused</param>
        private void _tbNewMessage_TextChanged(object sender, RoutedEventArgs e)
        {
            TextBox tb = (TextBox)sender;
            if (tb.Text.Contains("\r\n"))
            {             
                _SendText_Click(sender, e);
            }
        }


        /// <summary>
        /// The event the NetworkManager registers for so it knows when a text message is being sent.
        /// </summary>
        internal event EventHandler<ChatChangedEventArgs> SendingText;

        /// <summary>
        /// This listens for the Send message button click and raises the SendingTextEvent.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _SendText_Click(object sender, RoutedEventArgs e)
        {
            if (SendingText != null)
            {
                SendingText(sender, new ChatChangedEventArgs(SendText.Text + "\n"));
            }
            SendText.Clear();
        }

        /// <summary>
        /// This function is called when a text message is received.
        /// Add the message to the textbox
        /// </summary>
        /// <param name="s">the incomming message.</param>
        public void mP2P_TextListener(String s)
        {
           UpdateTextbox(s);
        }

        
        /// <summary>
        /// A delegate used to force the function call _EnableControls onto the SendButton control's thread. 
        /// </summary>
        /// <param name="value"></param>
        private delegate void _EnableControlsHandler(bool value);

        /// <summary>
        /// Enables the Send button and SendText textbox.
        /// </summary>
        /// <param name="value"></param>
        private void _EnableControls(bool value)
        {
            if (SendText.CheckAccess())
            {
                SendButton.IsEnabled = value;
                SendText.IsEnabled = value;
            }
            else
            {
                SendText.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new _EnableControlsHandler(_EnableControls), value);
            }
        }

        /// <summary>
        /// A delegate used to force the function call _EnableControls onto the SendButton control's thread. 
        /// </summary>
        /// <param name="message"></param>
        private delegate void _UpdateTextboxHandler(String message);

        /// <summary>
        /// Updates the textbox with a new message
        /// </summary>
        /// <param name="message">the new message</param>
        internal void UpdateTextbox(string message)
        {
            if (MessageLog.CheckAccess())
            {
                // The calling thread owns the dispatcher, and hence the UI element
                MessageLog.Text += message;
                MessageLog.ScrollToEnd();
            }
            else
            {
                // Invocation required
                MessageLog.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new _UpdateTextboxHandler(UpdateTextbox), message);
            }
        }

        /// <summary>
        /// This function is called by the network manager when the network status changes.
        /// </summary>
        /// <param name="userName">The current network managers user name</param>
        /// <param name="e">the status changed event args received</param>
        internal void SetStatusChanged(string userName, StatusChangedEventArgs e)
        {            
            if (userName == e.Member && e.NewNodeJoined)
            {
                //just joined...
                Utility.SetLabelText(lblFromValue, userName);             
                _EnableControls(true);
            }

            if (userName == e.Member && e.NodeLeft)
            {
                _EnableControls(false);
            }
        }

        /// <summary>
        /// Updates the textbox with a new message.
        /// </summary>
        /// <param name="s"></param>
        internal void MessageReceived(string s)
        {
            UpdateTextbox(s);
        }
    }
}
